package com.zhou.message.controller;


import com.zhou.framework.util.PageUtil;
import com.zhou.framework.util.SessionUtil;
import com.zhou.framework.util.SettingUtil;
import com.zhou.util.*;
import com.zhou.util.img.Base64Image;
import com.zhou.framework.aop.anotation.LogOption;
import com.zhou.framework.aop.enums.LogLevel;
import com.zhou.framework.dto.IntegersDto;
import com.zhou.framework.exception.VerifyException;
import com.zhou.framework.jwt.annotation.PassToken;
import com.zhou.framework.model.RS;
import com.zhou.framework.util.FileUploaderUtil;
import com.zhou.message.dao.Attachment;
import com.zhou.message.dto.AttachmentAddDto;
import com.zhou.message.dto.AttachmentDto;
import com.zhou.message.dto.AttachmentQueryDto;
import com.zhou.message.dto.AttachmentUpdateDto;
import com.zhou.message.service.AttachmentService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author lang.zhou
 * @since 2023-03-01
 */
@Api(tags = "系统附件接口")
@Slf4j
@RestController
@RequestMapping("/sys/attach")
public class AttachmentController {

    @Autowired
    private AttachmentService attachmentService;

    @PostMapping("/list")
    @ApiOperation("附件列表")
    @LogOption(LogLevel.QUERY)
    public Object list(@RequestBody AttachmentQueryDto dto){

        PageUtil.offsetPage(dto);
        List<AttachmentDto> list = attachmentService.getAttachList(dto);
        return PageUtil.result(dto,list);
    }

    @DeleteMapping("/delete")
    @ApiOperation("批量删除附件")
    @LogOption(LogLevel.DELETE)
    public Object delete(@RequestBody IntegersDto dto){
        log.warn("{}删除附件：{}",SessionUtil.getCurrentUserRealName(),dto.getIds());
        attachmentService.deleteAttach(dto.getIds());
        return RS.success();
    }

    @PostMapping("/download")
    @ApiOperation("下载附件")
    @LogOption(LogLevel.FILE)
    public void download(@RequestParam("id")Integer id, HttpServletResponse response) throws IOException {
        AttachmentDto info = attachmentService.getAttachDto(id);
        /*User user = SessionUtil.getCurrentUser().getUser();
        //如果当前下载的附件不是公开附件，且不属于当前用户
        if(!Objects.equals(info.getIsPub(),1) && !Objects.equals(user.getUserId(),info.getUserId())){

            List<Integer> ids = OrgUtil.adminOrgIds();
            if(ids == null || !ids.contains(user.getOrgId())){
                info = null;
            }
        }*/

        Assert.notNull(info,"附件不存在");
        InputStream stream = attachmentService.getAttachStream(id);

        WebUtil.download(response,stream,info.getFileName());
    }

    @PostMapping("/downloadVersion")
    @ApiOperation("下载附件")
    @LogOption(LogLevel.FILE)
    public void downloadVersion(@RequestParam String version, HttpServletResponse response) throws IOException {
        Attachment info = attachmentService.getVersionAttach(version);
        if(info!= null){
            WebUtil.download(response,info.getFile(),info.getFileName());
        }
    }

    @GetMapping("/viewData")
    @ApiOperation("预览附件数据")
    @LogOption(LogLevel.FILE)
    public void beforeView(@RequestParam("id")Integer id, HttpServletResponse response) throws Exception {
        Attachment attach = attachmentService.getAttachById(id);
        if(attach != null){
            if(FileUtil.isPhoto(attach.getPrefix())){
                WebUtil.writeStream(response,attach.getFile());
            }else if(FileUtil.isVideo(attach.getPrefix())){
                WebUtil.writeStream(response,attach.getFile());
            }else if(attach.getPrefix().endsWith("MP3") || attach.getPrefix().endsWith("KGMA")){
                WebUtil.writeStream(response,attach.getFile());
            }
        }
    }

    @GetMapping("/pubGet")
    @ApiOperation("预览开放的附件")
    @LogOption(LogLevel.OFF)
    @PassToken
    public void pubGet(@RequestParam("id")Integer id, HttpServletResponse response) throws Exception {
        Attachment attach = attachmentService.getAttachById(id);
        if(attach != null){
            if(Objects.equals(attach.getIsPub(),1) || SessionUtil.isLogin()){
                if(FileUtil.isPhoto(attach.getPrefix())){
                    WebUtil.writeStream(response,attach.getFile());
                }else if(FileUtil.isVideo(attach.getPrefix())){
                    WebUtil.writeStream(response,attach.getFile());
                }else if(attach.getPrefix().endsWith("MP3") || attach.getPrefix().endsWith("KGMA")){
                    WebUtil.writeStream(response,attach.getFile());
                }else{
                    WebUtil.download(response,attach.getFile(),attach.getFileName());
                }
            }

        }
    }


    @ApiOperation("修改附件")
    @PostMapping(value = "/update")
    @LogOption(LogLevel.FILE)
    public Object updateAttach(@Validated @RequestBody AttachmentUpdateDto dto) throws Exception{
        Attachment attach = attachmentService.getAttachById(dto.getId());
        Assert.notNull(attach,"附件不存在【id=%s】",dto.getId());
        File file = null;
        if(ObjectUtil.isNotEmpty(dto.getFileIds())){
            file = FileUploaderUtil.decodeFile(ListUtil.getFirst(dto.getFileIds()));
        }

        boolean b = SettingUtil.getBoolean("uploader", "md5Check", false);
        if(file != null && b){
            byte[] data = FileUtils.readFileToByteArray(file);
            String md5 = Md5Util.hex(data);
            int n = attachmentService.getAttachCountByMd5(md5);
            if(n > 0){
                return RS.failed("附件列表中存在内容重复的文件");
            }
            attach.setFile(data);
            attach.setMd5(md5);
            String prefix = FileUtil.getPrefix(file.getName());
            if(prefix != null){
                attach.setPrefix(prefix.toUpperCase());
            }
            attach.setFileName(FilenameUtils.getName(file.getName()));
            attach.setSize((long) data.length);
        }
        log.warn(SessionUtil.getCurrentUserRealName()+"修改附件");

        attach.setIsPub(dto.getIsPub());
        attach.setDescription(dto.getDescription());
        attach.setSource(dto.getSource());
        attach.setSourceId(dto.getSourceId());
        attachmentService.updateAttach(attach);
        return RS.success();
    }

    @PostMapping("/img2Base64")
    @ApiOperation("图片转base64")
    @LogOption(LogLevel.FILE)
    public Object img2Base64(@RequestParam MultipartFile file) throws Exception{
        try{
            String name = FilenameUtils.getName(file.getOriginalFilename());

            byte[] bytes = this.checkFile(file,name);
            if(StringTool.isBlank(name)){
                name = new Date().getTime() + ".jpeg";
            }

            Base64Image image = new Base64Image(bytes,FileUtil.getPrefix(name));
            return RS.data(image.getFullString());
        }catch (VerifyException e){
            return RS.failed(e.getMessage());
        }catch (Exception e){
            log.error("获取图片失败：",e);
            return RS.failed("获取图片失败");
        }
    }

    @PostMapping("/add")
    @ApiOperation("新增附件")
    @LogOption(LogLevel.FILE)
    public Object addAttach(@Validated @RequestBody AttachmentAddDto dto) throws Exception{
        String fileId = ListUtil.getFirst(dto.getFileIds());
        boolean b = SettingUtil.getBoolean("uploader", "md5Check", false);
        File file = FileUploaderUtil.decodeFile(fileId);
        Attachment attach = FileUploaderUtil.file2Attach(file);
        String md5 = Md5Util.hex(FileUtils.readFileToByteArray(file));
        if(b){
            int n = attachmentService.getAttachCountByMd5(md5);
            if(n > 0){
                return RS.failed("附件列表中存在内容重复的文件");
            }
        }
        attach.setIsPub(dto.getIsPub());
        attach.setSource(dto.getSource());
        attach.setSourceId(dto.getSourceId());
        attach.setDescription(dto.getDescription());
        Integer userId = dto.getUserId();
        if(ObjectUtil.isEmpty(userId)){
            userId = SessionUtil.getCurrentUserId();
        }
        attach.setUserId(userId);
        attachmentService.addAttach(attach);
        return RS.success();
    }

    private byte[] checkFile(MultipartFile cf, String name) throws Exception{
        Map<String, Object> uploader = SettingUtil.getSettingMap("uploader");

        double cfgSize = Math.max(MapUtils.getDoubleValue(uploader,"maxFileSize",10D), 0.001D);
        long maxSize = (long) (cfgSize * 1024 * 1024);
        long size = cf.getSize();
        //result.put("maxSize",maxSize+"Kb");
        Assert.isTrue(size <= maxSize,"文件最大为%skb",maxSize/1024);

        //fileName = cf.getOriginalFilename();
        byte[] bytes = cf.getBytes();

        name = FilenameUtils.getName(name);
        List<String> allowType = new ArrayList<>(0);
        String allowTypeStr = MapUtils.getString(uploader,"acceptType","").trim().replace("，",",").toUpperCase();
        //result.put("allowType",allowTypeStr);
        if(StringTool.isNotEmpty(allowTypeStr)){
            allowType = Arrays.asList(allowTypeStr.split(","));
        }
        String extension = FilenameUtils.getExtension(name).toUpperCase();
        //不支持的文件类型！
        Assert.isTrue(extension.length() > 0 && allowType.contains(extension),"文件类型错误");
        return bytes;
    }

    /**
     * 上传控件上传文件
     */
    @PostMapping("/uploadTemp")
    @ApiOperation("上传临时文件")
    public Object uploadTemp(@RequestParam("file") MultipartFile cf,@RequestParam("name") String name) {
        RS result = RS.success();
        try{
            //请选择非空文件！
            Assert.isTrue(!cf.isEmpty(),"请选择非空文件");

            byte[] bytes = this.checkFile(cf,name);

            String dirPath = FileUploaderUtil.createPath();
            File dir = new File(dirPath);

            Assert.isTrue(dir.isDirectory() || dir.mkdirs(),"系统无法在服务器上创建临时路径，请检查用户文件夹权限");

            File file = new File(dirPath + "/" + name);

            FileUtil.saveFile(bytes,file);
            //文件保存出错！
            Assert.fileExist(file,"保存文件时出错");
            String s = FileUploaderUtil.encodePath(file.getAbsolutePath());

            result.put("uuid",s);
            return result;
        }catch (VerifyException e){
            return RS.failed(e.getMessage());
        }catch (Exception e){
            return RS.failed("上传失败");
        }
    }


    @DeleteMapping("/deleteTemp")
    @ApiOperation("删除临时文件")
    public void deleteTemp(@RequestParam("uuid") String id) {
        String path = FileUploaderUtil.decodePath(id);
        File file = new File(path);
        if(file.isFile()){
            FileUtil.safeDelete(file);
        }
    }

}

